import os
from flask import current_app
from sqlalchemy import desc
from apps.extensions import db
from apps.extensions.init_upload import photos, documents, archives, audio, video, attachment, others, allfiles, ALLOWED_EXTENSIONS
from apps.modules.admin.models import Photo
from apps.modules.admin.schemas import PhotoOutSchema
from apps.common.curd import model_to_dicts


def get_photo(page, limit, name=None, mime=None):
    query = Photo.query
    
    # 添加搜索条件
    if name:
        query = query.filter(Photo.name.like(f'%{name}%'))
    
    if mime:
        # 根据文件类型过滤
        if mime == 'image':
            query = query.filter(Photo.mime.like('image/%'))
        elif mime == 'video':
            query = query.filter(Photo.mime.like('video/%'))
        elif mime == 'audio':
            query = query.filter(Photo.mime.like('audio/%'))
        elif mime == 'document':
            query = query.filter(
                Photo.mime.like('application/pdf') |
                Photo.mime.like('application/msword') |
                Photo.mime.like('application/vnd.openxmlformats-officedocument.wordprocessingml.document') |
                Photo.mime.like('application/vnd.ms-excel') |
                Photo.mime.like('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') |
                Photo.mime.like('application/vnd.ms-powerpoint') |
                Photo.mime.like('application/vnd.openxmlformats-officedocument.presentationml.presentation')
            )
        elif mime == 'other':
            query = query.filter(
                ~Photo.mime.like('image/%') &
                ~Photo.mime.like('video/%') &
                ~Photo.mime.like('audio/%') &
                ~Photo.mime.like('application/pdf') &
                ~Photo.mime.like('application/msword') &
                ~Photo.mime.like('application/vnd.openxmlformats-officedocument.wordprocessingml.document') &
                ~Photo.mime.like('application/vnd.ms-excel') &
                ~Photo.mime.like('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') &
                ~Photo.mime.like('application/vnd.ms-powerpoint') &
                ~Photo.mime.like('application/vnd.openxmlformats-officedocument.presentationml.presentation')
            )
    
    photo = query.order_by(desc(Photo.create_time)).paginate(page=page, per_page=limit, error_out=False)
    count = query.count()
    data = model_to_dicts(schema=PhotoOutSchema, data=photo.items)
    return data, count


def upload_one(photo, mime):
    filename = photos.save(photo)
    file_url = '/static/upload/images/' + filename
    # file_url = photos.url(filename)
    upload_url = current_app.config.get("UPLOADED_PHOTOS_DEST")
    size = os.path.getsize(upload_url + '/' + filename)
    photo = Photo(name=filename, href=file_url, mime=mime, size=size)
    db.session.add(photo)
    db.session.commit()
    return file_url


def delete_photo_by_id(_id):
    # photo_name = Photo.query.filter_by(id=_id).first().name
    # upload_url = current_app.config.get("UPLOADED_PHOTOS_DEST")
    # os.remove(upload_url + '/' + photo_name)
    Photo.query.filter_by(id=_id).delete()
    db.session.commit()


# 新增：通用文件上传函数
def upload_file_by_type(file, mime, file_type='all_files', save_to_db=True):
    """
    根据文件类型上传文件
    
    Args:
        file: 上传的文件对象
        mime: 文件的MIME类型
        file_type: 文件类型 ('photos', 'documents', 'archives', 'audio', 'video', 'others', 'all_files')
        save_to_db: 是否保存到数据库
    
    Returns:
        dict: 包含文件信息的字典
    """
    try:
        # 验证文件对象
        if not file or not hasattr(file, 'filename'):
            raise ValueError("无效的文件对象")
        
        # 验证文件名
        if not file.filename:
            raise ValueError("文件名不能为空")
        
        upload_sets = {
            'images': photos,  # 统一使用 'images' 作为键名
            'documents': documents,
            'archives': archives,
            'audio': audio,
            'video': video,
            'attachment': attachment,  # 附件类型
            'others': others,
            'all_files': allfiles
        }
        
        if file_type not in upload_sets:
            raise ValueError(f"不支持的文件类型: {file_type}")
        
        upload_set = upload_sets[file_type]
        
        # 检查文件扩展名是否允许
        extension = get_file_extension(file.filename)
        if not extension:
            raise ValueError(f"文件 {file.filename} 没有有效的扩展名")
        
        # 验证文件类型
        if file_type != 'all_files':
            allowed_extensions = ALLOWED_EXTENSIONS.get(file_type, ())
            if extension not in allowed_extensions:
                raise ValueError(f"文件类型 {file_type} 不支持扩展名 {extension}")
        
        # 确保上传目录存在
        if file_type == 'all_files':
            dest_config = "UPLOADED_ALLFILES_DEST"
        elif file_type == 'images':
            dest_config = "UPLOADED_PHOTOS_DEST"  # images 类型使用 PHOTOS 配置
        elif file_type == 'attachment':
            dest_config = "UPLOADED_ATTACHMENT_DEST"  # attachment 类型使用 ATTACHMENT 配置
        else:
            dest_config = f"UPLOADED_{file_type.upper()}_DEST"
        upload_dest = current_app.config.get(dest_config, f"apps/modules/admin/static/upload/{file_type}")
        
        # 创建目录（如果不存在）
        os.makedirs(upload_dest, exist_ok=True)
        
        # 保存文件 - 使用更安全的方法
        try:
            filename = upload_set.save(file)
        except Exception as save_error:
            # 如果Flask-Uploads保存失败，尝试直接保存
            current_app.logger.warning(f"Flask-Uploads保存失败，尝试直接保存: {save_error}")
            
            # 生成安全的文件名
            import uuid
            import time
            original_filename = file.filename
            extension = get_file_extension(original_filename)
            safe_filename = f"{int(time.time())}_{uuid.uuid4().hex[:8]}.{extension}"
            
            # 直接保存文件
            file_path = os.path.join(upload_dest, safe_filename)
            file.save(file_path)
            filename = safe_filename
            
            current_app.logger.info(f"直接保存成功: {filename}")
        
        # 构建文件URL
        file_url = f'/static/upload/{file_type}/{filename}'
        
        # 获取文件大小
        file_path = os.path.join(upload_dest, filename)
        size = os.path.getsize(file_path) if os.path.exists(file_path) else 0
        
        # 保存到数据库（可选）
        if save_to_db:
            try:
                photo = Photo(name=filename, href=file_url, mime=mime, size=size)
                db.session.add(photo)
                db.session.commit()
            except Exception as db_error:
                current_app.logger.warning(f"数据库保存失败，但文件已上传: {db_error}")
                # 即使数据库保存失败，也返回文件信息
        
        return {
            'filename': filename,
            'url': file_url,
            'size': size,
            'mime': mime,
            'type': file_type
        }
        
    except Exception as e:
        # 记录详细的错误信息
        import traceback
        error_msg = str(e) if str(e) else f"异常类型: {type(e).__name__}"
        error_traceback = traceback.format_exc()
        
        current_app.logger.error(f"文件上传失败: {error_msg}")
        current_app.logger.error(f"文件类型: {file_type}, 文件名: {file.filename if file else 'None'}")
        current_app.logger.error(f"错误详情: {error_traceback}")
        
        # 记录更多调试信息
        current_app.logger.error(f"文件对象类型: {type(file).__name__}")
        current_app.logger.error(f"上传集合类型: {type(upload_set).__name__}")
        current_app.logger.error(f"目标目录: {upload_dest}")
        
        raise ValueError(f"文件上传失败: {error_msg}")


def get_file_extension(filename):
    """获取文件扩展名"""
    return filename.rsplit('.', 1)[1].lower() if '.' in filename else ''


def is_allowed_file(filename, file_type='all_files'):
    """
    检查文件是否允许上传
    
    Args:
        filename: 文件名
        file_type: 文件类型
    
    Returns:
        bool: 是否允许上传
    """
    if file_type not in ALLOWED_EXTENSIONS:
        return False
    
    extension = get_file_extension(filename)
    return extension in ALLOWED_EXTENSIONS[file_type]


def get_allowed_extensions(file_type='all_files'):
    """
    获取指定类型允许的文件扩展名
    
    Args:
        file_type: 文件类型
    
    Returns:
        tuple: 允许的文件扩展名列表
    """
    return ALLOWED_EXTENSIONS.get(file_type, ())


def get_file_type_by_extension(filename):
    """
    根据文件扩展名判断文件类型
    
    Args:
        filename: 文件名
    
    Returns:
        str: 文件类型
    """
    extension = get_file_extension(filename)
    
    for file_type, extensions in ALLOWED_EXTENSIONS.items():
        if extension in extensions:
            return file_type
    
    return 'others'  # 默认归类为其他类型


def delete_file_by_id(_id):
    """
    根据ID删除文件
    
    Args:
        _id: 文件ID
    """
    photo = Photo.query.filter_by(id=_id).first()
    if not photo:
        return False
    
    filename = photo.name
    file_type = get_file_type_by_extension(filename)
    
    # 获取对应的上传目录
    if file_type == 'all_files':
        dest_config = "UPLOADED_ALLFILES_DEST"
    elif file_type == 'images':
        dest_config = "UPLOADED_PHOTOS_DEST"  # images 类型使用 PHOTOS 配置
    elif file_type == 'attachment':
        dest_config = "UPLOADED_ATTACHMENT_DEST"  # attachment 类型使用 ATTACHMENT 配置
    else:
        dest_config = f"UPLOADED_{file_type.upper()}_DEST"
    upload_dest = current_app.config.get(dest_config, f"apps/modules/admin/static/upload/{file_type}")
    
    # 删除物理文件
    file_path = os.path.join(upload_dest, filename)
    if os.path.exists(file_path):
        os.remove(file_path)
    
    # 删除数据库记录
    Photo.query.filter_by(id=_id).delete()
    db.session.commit()
    
    return True
